//Copyright (C) 2007 James Ashley (www.imaginativeuniversal.com) under the terms of the LGPL.
using System;
using System.Collections.Generic;
using System.Speech.Recognition;
using System.Text;
using System.IO;


namespace SophiaBot
{
    public class PlayGameTransitionDialogBot: BotServerBase
    {
        #region local fields

        protected System.Collections.Specialized.StringCollection gameCollection = new System.Collections.Specialized.StringCollection();
        protected string _gameDataFolderPath = string.Empty;
        protected string _status = "No game selected.";
        protected bool _isWaitingForGameChoice = false;

        #endregion

        #region constructor

        public PlayGameTransitionDialogBot()
        {
            _name = "Play Game Transition"; 
        }
        #endregion

        #region IBotServer Members


        /// <summary>
        /// Reads the specified input text.
        /// </summary>
        /// <param name="inputText">The input text.</param>
        public override void Read(string inputText)
        {
            if (!_isRunning || HandleDialogResponse(FormatInputForDisplay(inputText)) == false)
            {
                if (null != _nextBot)
                    _nextBot.Read(inputText);
            }
        }

        /// <summary>
        /// Gets the grammar.
        /// </summary>
        /// <returns></returns>
        public override Grammar[] GetGrammars()
        {
            Grammar g = GetPlayGameGrammar();
            Grammar h = GetGameListGrammar();
            g.Name = this.Name;
            h.Name = this.Name;
            g.Priority = this._priority;
            h.Priority = this._priority;
            g.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(TransitionDialog_SpeechRecognized);
            h.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(TransitionDialog_SpeechRecognized); 
            return new Grammar[2] { g,h };
        }

        /// <summary>
        /// Gets the status.
        /// </summary>
        /// <returns></returns>
        public override string GetStatus()
        {
            return _status;
        }

        /// <summary>
        /// Starts this instance.
        /// </summary>
        public override void Start()
        {
            LoadGameCollection();
            base.Start();
        }


        /// <summary>
        /// Starts the specified game data folder path.
        /// </summary>
        /// <param name="gameDataFolderPath">The game data folder path.</param>
        public override void Start(string gameDataFolderPath)
        {
            _gameDataFolderPath = gameDataFolderPath;
            this.Start();
        }

        /// <summary>
        /// Stops this instance.
        /// </summary>
        public override void Stop()
        {
            base.Stop();
        }

        #endregion

        #region helper methods and properties

        /// <summary>
        /// Gets the game list grammar.
        /// </summary>
        /// <returns></returns>
        protected virtual Grammar GetGameListGrammar() 
        {
            Choices choices = new Choices();
            //add game names
            foreach (string game in gameCollection)
            {
                string g = game;
                if (game.IndexOf(".") > -1)
                    g = game.Substring(0, game.LastIndexOf("."));
                choices.Add(g.ToUpper());
            }
            //add game numbers
            for (int i = gameCollection.Count; i > 0; i--)
            {
                choices.Add(TranslateNumberToWord(i.ToString()).ToUpper());
            }
            return new Grammar(new GrammarBuilder(choices));

        }

        /// <summary>
        /// Gets the play game grammar.
        /// </summary>
        /// <returns></returns>
        protected virtual Grammar GetPlayGameGrammar()
        {
            Choices choices = new Choices();
            GrammarBuilder playGameCommand = null;

            playGameCommand = new GrammarBuilder();
            playGameCommand.AppendWildcard();
            playGameCommand.Append("PLAY A GAME");
            choices.Add(playGameCommand);

            playGameCommand = new GrammarBuilder();
            playGameCommand.Append("PLAY A GAME");
            playGameCommand.AppendWildcard();
            choices.Add(playGameCommand);

            playGameCommand = new GrammarBuilder();
            playGameCommand.AppendWildcard();
            playGameCommand.Append("PLAY GAME");
            choices.Add(playGameCommand);

            playGameCommand = new GrammarBuilder();
            playGameCommand.Append("PLAY GAME");
            playGameCommand.AppendWildcard();
            choices.Add(playGameCommand);

            choices.Add("LOAD FILES");

            return new Grammar(new GrammarBuilder(choices));

        }

        /// <summary>
        /// Translates the number to word.
        /// </summary>
        /// <param name="number">The number.</param>
        /// <returns></returns>
        protected string TranslateNumberToWord(string number)
        {
            int tmpNumber = 0;
            if (!int.TryParse(number, out tmpNumber))
                return number;

            tmpNumber = (int)Math.Abs(tmpNumber);
            string[] ones = new string[10] {"", "one", "two","three", "four","five","six","seven","eight","nine"};
            string[] teens = new string[10] { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
            string[] tens = new string[10] { "", "ten", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety" };

            if (number == "0")
                return "zero";

            if (tmpNumber >= 100 && tmpNumber < 1000)
            {
                number = ones[tmpNumber / 100] + " hundred ";
                if (tmpNumber % 100 != 0)
                {
                    string newNum = TranslateNumberToWord((tmpNumber % 100).ToString());
                    number = (number + newNum).Trim();
                }
            }
            else if (tmpNumber >= 20 && tmpNumber < 100)
            {
                number = tens[(tmpNumber/10)];
                if (tmpNumber % 10 != 0)
                    number = number + "-" + ones[tmpNumber % 10];
            }
            else if (tmpNumber < 20 && tmpNumber >= 10)
            {
                number = teens[tmpNumber - 10];
            }
            else if (tmpNumber < 10)
            {
                number = ones[tmpNumber];
            }
            return number;
        }

        /// <summary>
        /// Transforms Text to Number.
        /// </summary>
        /// <param name="input">The input.</param>
        protected void TranslateWordToNumber(ref string word)
        {
            string[] teens = new string[10] { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
            string[] singles = new string[10] { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" };
            string[] hyphenatedtens = new string[8] { "twenty-", "thirty-", "fourty-", "fifty-", "sixty-", "seventy-", "eighty-", "ninety-" };
            string[] tens = new string[8] { "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety" };
            word = word.ToLower();
            for (int i = 0; i < teens.Length; i++)
            {
                word = word.Replace(teens[i], (i + 10).ToString());
            }
            for (int i = 0; i < singles.Length; i++)
            {
                word = word.Replace(singles[i], (i + 1).ToString());
            }
            for (int i = 0; i < hyphenatedtens.Length; i++)
            {
                word = word.Replace(hyphenatedtens[i], (i + 2).ToString());
            }
            for (int i = 0; i < tens.Length; i++)
            {
                word = word.Replace(tens[i], (i + 2).ToString());
            }
        }

        /// <summary>
        /// Handles the dialog response.
        /// </summary>
        /// <param name="inputText">The input text.</param>
        /// <returns></returns>
        protected virtual bool HandleDialogResponse(string inputText)
        {
                if (!_isWaitingForGameChoice)
                {
                    if (inputText.IndexOf("LOAD FILES",StringComparison.CurrentCultureIgnoreCase)>-1 || (inputText.IndexOf("play", StringComparison.CurrentCultureIgnoreCase) > -1 && inputText.IndexOf("game", StringComparison.CurrentCultureIgnoreCase) > -1))
                    {
                        StringBuilder sb = new StringBuilder();
                        LoadGameCollection();
                        //process as a unit
                        lock (staticLock)
                        {
                            RaiseBotResponseEvent(this, "Shall we play a game?\n");
                            int i = 0;
                            foreach (string game in gameCollection)
                            {
                                i++;
                                string g = game;
                                //strip out file extension
                                if (game.IndexOf(".") > -1)
                                    g = game.Substring(0, game.LastIndexOf("."));

                                sb.Append(i.ToString() + ". " + g + "\n");
                            }
                            _status = "Please select a game...";
                            RaiseBotInfoResponseEvent(this, sb.ToString());
                            _isWaitingForGameChoice = true;
                        }
                        return true;
                    }
                    else
                        return false;
                }
                else
                {
                    _isWaitingForGameChoice = false;

                    //trim file name
                    if (inputText.IndexOf(".") > -1)
                        inputText = inputText.Substring(0, inputText.LastIndexOf("."));

                    TranslateWordToNumber(ref inputText);

                    if (inputText.IndexOf("Global Thurmonuclear War",StringComparison.CurrentCultureIgnoreCase)>-1 || inputText.IndexOf(gameCollection.Count.ToString()) > -1)
                    {
                        RaiseBotResponseEvent(this, "Kaboom!");
                        _status = "Global Thurmonuclear War selected.";
                        DebugWriteToConsole(_status);
                        return true;
                    }

                    for (int i = gameCollection.Count - 1; i > 0; i--)
                    {
                        if (inputText.IndexOf(i.ToString()) > -1 || inputText.IndexOf(TranslateNumberToWord(i.ToString())) > -1 || inputText.IndexOf(gameCollection[i - 1], StringComparison.CurrentCultureIgnoreCase) > -1 || gameCollection[i - 1].IndexOf(inputText, StringComparison.CurrentCultureIgnoreCase) > -1)
                        {
                            //matched game title or enumeration
                            if (null != OnLoadGame)
                                OnLoadGame(GameDataFolderPath + gameCollection[i - 1]);

                            _status = gameCollection[i - 1] + " selected.";
                            this.Stop();
                            DebugWriteToConsole(_status);
                            return true;
                        }
                    }
                    // if it got this far, we didn't handle it, so give it back to the bot
                    _status = "Play game dialog cancelled.";
                    DebugWriteToConsole(_status);
                    return false;
                }
        }

        /// <summary>
        /// Loads the game collection.
        /// </summary>
        protected virtual void LoadGameCollection()
        {
            if(gameCollection.Count > 0)
                gameCollection.Clear();

            foreach (string filename in Directory.GetFiles(GameDataFolderPath))
            {
                //get file name with path information
                string f = filename.Substring(filename.LastIndexOf("\\") + 1);
                gameCollection.Add(f);
            }

            gameCollection.Add("Global Thermonuclear War");
        }

        /// <summary>
        /// Handles the SpeechRecognized event of the Tansition Dialog Grammar.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Speech.Recognition.SpeechRecognizedEventArgs"/> instance containing the event data.</param>
        public virtual void TransitionDialog_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            string resultText = e.Result.Text;
            RaiseTextRecognizedEvent(resultText);
            DebugWriteToConsole(resultText + " Recognized in Dialog bot Grammar");
            resultText = FormatProperCase(resultText);
            Read(resultText);
        }

        #endregion

        #region public methods and properties

        public event GenericEventHandler<string> OnLoadGame;

        /// <summary>
        /// Gets or sets the game data folder path.
        /// </summary>
        /// <value>The game data folder path.</value>
        public string GameDataFolderPath
        {
            get { return _gameDataFolderPath; }
            set { _gameDataFolderPath = value; }
        }

        #endregion
    }
}
